package node;
import java.util.*;
import func.*;

public class Tree {

	private final double fpr = 0.5;
	private final double ppr = 0.6;
	private double probchange;
	private double probswap;
	private Random ran = new Random();
	private Function[] func;
	
	public Tree() {
		this(0.1, 0.7, FunctionFactory.getFunctions());
	}
	
	public Tree(double probchange, double probswap, Function[] func) {
		this.probchange = probchange;
		this.probswap = probswap;
		this.func = func;
	}
	
	public Node crossover(Node node1, Node node2, boolean top) {
		if(ran.nextDouble() < probswap && !top)
			return node2.copyNode();
		else {
			Node result = node1.copyNode();
			if(node1 instanceof FuncNode && node2 instanceof FuncNode) {
				FuncNode fn1 = (FuncNode) result;
				FuncNode fn2 = (FuncNode) node2;
				
				int i = ran.nextInt(fn2.numberOfChildren());
				ArrayList<Node> children = new ArrayList<Node>(3);
				for(Node child : fn1)
					children.add(crossover(child, fn2.getChild(i), false));
					
				fn1.setChildren(children);
			}
			
			return result;
		}
	}
	
	public Node mutate(Node node, int pc) {
		if(ran.nextDouble() < probchange)
			return makeRandomTree(pc, 4);
		else {
			Node result = node.copyNode();
			if(result instanceof FuncNode) {
				FuncNode fn = (FuncNode) result;
				ArrayList<Node> children = new ArrayList<Node>(3);
				for(Node child : fn)
					children.add(mutate(child, pc));
				
				fn.setChildren(children);
				return fn;
			}
			
			return result;
		}
	}
	
	public Node makeRandomTree(int pc, int maxdepth) {
		if(ran.nextDouble() < fpr && maxdepth > 0) {
			int i = ran.nextInt(func.length);
			Function f = func[i];
			ArrayList<Node> children = new ArrayList<Node>(3);
			for(int j = 0; j < f.getChildcount(); j++)
				children.add(makeRandomTree(pc, maxdepth - 1));
			
			return new FuncNode(f, children);
		}
		else if(ran.nextDouble() < ppr)
			return new ParamNode(ran.nextInt(pc));
		else
			return new ConstNode(ran.nextInt(10));
	}
}
